from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
from django.http import HttpResponse
from .models import Host, HostGroup, Project, Environment, User, UserGroup, Recipient
from .serializers import (
    HostSerializer, HostGroupSerializer, ProjectSerializer,
    EnvironmentSerializer, UserSerializer, UserGroupSerializer, RecipientSerializer
)
import paramiko
import re
from openpyxl import Workbook, load_workbook
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile


class HostViewSet(viewsets.ModelViewSet):
    """主机管理"""
    queryset = Host.objects.all()
    serializer_class = HostSerializer
    
    @action(detail=True, methods=['get'])
    def check_status(self, request, pk=None):
        """检测单个主机的实际在线状态"""
        host = self.get_object()
        
        try:
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            connect_kwargs = {
                'hostname': host.ip,
                'port': host.port,
                'username': host.username,
                'timeout': 5
            }
            
            if host.password:
                connect_kwargs['password'] = host.password
            elif host.ssh_key:
                from io import StringIO
                key_file = StringIO(host.ssh_key)
                connect_kwargs['pkey'] = paramiko.RSAKey.from_private_key(key_file)
            
            client.connect(**connect_kwargs)
            client.close()
            
            # 更新主机状态为在线
            host.status = 'online'
            host.save()
            
            return Response({
                'status': 'online',
                'message': '主机在线',
                'reachable': True
            })
            
        except Exception as e:
            # 更新主机状态为离线
            host.status = 'offline'
            host.save()
            
            return Response({
                'status': 'offline',
                'message': f'主机离线: {str(e)}',
                'reachable': False
            })
    
    @action(detail=False, methods=['post'])
    def check_all_status(self, request):
        """批量检测所有主机的实际在线状态"""
        hosts = Host.objects.all()
        results = []
        
        for host in hosts:
            try:
                client = paramiko.SSHClient()
                client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                
                connect_kwargs = {
                    'hostname': host.ip,
                    'port': host.port,
                    'username': host.username,
                    'timeout': 5
                }
                
                if host.password:
                    connect_kwargs['password'] = host.password
                elif host.ssh_key:
                    from io import StringIO
                    key_file = StringIO(host.ssh_key)
                    connect_kwargs['pkey'] = paramiko.RSAKey.from_private_key(key_file)
                
                client.connect(**connect_kwargs)
                client.close()
                
                # 更新为在线
                if host.status != 'online':
                    host.status = 'online'
                    host.save()
                
                results.append({
                    'id': host.id,
                    'hostname': host.hostname,
                    'ip': host.ip,
                    'status': 'online',
                    'reachable': True
                })
                
            except Exception as e:
                # 更新为离线
                if host.status != 'offline':
                    host.status = 'offline'
                    host.save()
                
                results.append({
                    'id': host.id,
                    'hostname': host.hostname,
                    'ip': host.ip,
                    'status': 'offline',
                    'reachable': False,
                    'error': str(e)
                })
        
        online_count = len([r for r in results if r['reachable']])
        offline_count = len([r for r in results if not r['reachable']])
        
        return Response({
            'total': len(results),
            'online': online_count,
            'offline': offline_count,
            'results': results
        })
    
    @action(detail=False, methods=['get'])
    def stats(self, request):
        """获取主机统计信息"""
        total = Host.objects.count()
        online = Host.objects.filter(status='online').count()
        offline = Host.objects.filter(status='offline').count()
        maintenance = Host.objects.filter(status='maintenance').count()
        
        return Response({
            'total': total,
            'online': online,
            'offline': offline,
            'maintenance': maintenance
        })
    
    @action(detail=True, methods=['get'])
    def monitor(self, request, pk=None):
        """获取主机实时监控信息"""
        host = self.get_object()
        
        try:
            # 建立SSH连接
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            connect_kwargs = {
                'hostname': host.ip,
                'port': host.port,
                'username': host.username,
                'timeout': 5,
            }
            
            if host.password:
                connect_kwargs['password'] = host.password
            
            client.connect(**connect_kwargs)
            
            # 获取CPU使用率
            stdin, stdout, stderr = client.exec_command("top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1")
            cpu_usage = stdout.read().decode().strip()
            
            # 获取内存使用情况
            stdin, stdout, stderr = client.exec_command("free -m | grep Mem | awk '{print $3,$2}'")
            mem_output = stdout.read().decode().strip().split()
            mem_used = int(mem_output[0]) if len(mem_output) > 0 else 0
            mem_total = int(mem_output[1]) if len(mem_output) > 1 else 1
            mem_usage = round((mem_used / mem_total) * 100, 2)
            
            # 获取磁盘使用情况
            stdin, stdout, stderr = client.exec_command("df -h / | tail -1 | awk '{print $3,$2,$5}' | sed 's/%//'")
            disk_output = stdout.read().decode().strip().split()
            disk_used = disk_output[0] if len(disk_output) > 0 else '0G'
            disk_total = disk_output[1] if len(disk_output) > 1 else '0G'
            disk_usage = float(disk_output[2]) if len(disk_output) > 2 else 0
            
            # 获取系统信息
            stdin, stdout, stderr = client.exec_command("cat /etc/os-release | grep 'PRETTY_NAME' | cut -d'\"' -f2")
            os_version = stdout.read().decode().strip()
            if not os_version:
                stdin, stdout, stderr = client.exec_command("uname -sr")
                os_version = stdout.read().decode().strip()
            
            client.close()
            
            return Response({
                'cpu_usage': float(cpu_usage) if cpu_usage else 0,
                'mem_usage': mem_usage,
                'mem_used': mem_used,
                'mem_total': mem_total,
                'disk_usage': disk_usage,
                'disk_used': disk_used,
                'disk_total': disk_total,
                'os_version': os_version or 'Unknown'
            })
            
        except Exception as e:
            return Response({
                'error': str(e),
                'cpu_usage': 0,
                'mem_usage': 0,
                'mem_used': 0,
                'mem_total': 0,
                'disk_usage': 0,
                'disk_used': '0G',
                'disk_total': '0G',
                'os_version': 'Unknown'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    @action(detail=False, methods=['get'])
    def export(self, request):
        """导出主机信息到Excel"""
        try:
            hosts = Host.objects.all()
            
            # 创建工作簿
            wb = Workbook()
            ws = wb.active
            ws.title = "主机列表"
            
            # 设置表头
            headers = ['ID', '主机名', 'IP地址', '端口', '用户名', '状态', 
                      'CPU核心数', '内存(GB)', '磁盘(GB)', '操作系统', '描述', '创建时间']
            ws.append(headers)
            
            # 写入数据
            for host in hosts:
                row = [
                    host.id,
                    host.hostname,
                    host.ip,
                    host.port,
                    host.username,
                    host.get_status_display(),
                    host.cpu_cores or '',
                    host.memory_gb or '',
                    host.disk_gb or '',
                    host.os_version or '',
                    host.description or '',
                    host.created_at.strftime('%Y-%m-%d %H:%M:%S')
                ]
                ws.append(row)
            
            # 调整列宽
            for col in ws.columns:
                max_length = 0
                column = col[0].column_letter
                for cell in col:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                adjusted_width = min(max_length + 2, 50)
                ws.column_dimensions[column].width = adjusted_width
            
            # 保存到BytesIO
            output = BytesIO()
            wb.save(output)
            output.seek(0)
            
            # 返回文件
            response = HttpResponse(
                output.getvalue(),
                content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            response['Content-Disposition'] = 'attachment; filename=hosts_export.xlsx'
            return response
            
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    @action(detail=False, methods=['post'])
    def import_excel(self, request):
        """从Excel导入主机信息"""
        try:
            file = request.FILES.get('file')
            if not file:
                return Response({'error': '请上传文件'}, status=status.HTTP_400_BAD_REQUEST)
            
            # 读取Excel文件
            wb = load_workbook(file)
            ws = wb.active
            
            success_count = 0
            error_count = 0
            errors = []
            
            # 跳过表头，从第二行开始读取
            for row_idx, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2):
                try:
                    # 检查必填字段
                    if not row[2] or not row[1]:  # IP和主机名
                        errors.append(f'第{row_idx}行: IP地址和主机名不能为空')
                        error_count += 1
                        continue
                    
                    # 创建或更新主机
                    host_data = {
                        'hostname': row[1],
                        'ip': row[2],
                        'port': int(row[3]) if row[3] else 22,
                        'username': row[4] or 'root',
                        'status': 'online',  # 默认在线
                        'cpu_cores': int(row[6]) if row[6] else None,
                        'memory_gb': float(row[7]) if row[7] else None,
                        'disk_gb': float(row[8]) if row[8] else None,
                        'os_version': row[9] or '',
                        'description': row[10] or '',
                    }
                    
                    # 检查是否存在
                    existing = Host.objects.filter(ip=row[2]).first()
                    if existing:
                        # 更新
                        for key, value in host_data.items():
                            setattr(existing, key, value)
                        existing.save()
                    else:
                        # 创建
                        Host.objects.create(**host_data)
                    
                    success_count += 1
                    
                except Exception as e:
                    errors.append(f'第{row_idx}行: {str(e)}')
                    error_count += 1
            
            return Response({
                'success': True,
                'success_count': success_count,
                'error_count': error_count,
                'errors': errors
            })
            
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class HostGroupViewSet(viewsets.ModelViewSet):
    """主机组管理"""
    queryset = HostGroup.objects.all()
    serializer_class = HostGroupSerializer


class ProjectViewSet(viewsets.ModelViewSet):
    """项目管理"""
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer


class EnvironmentViewSet(viewsets.ModelViewSet):
    """环境管理"""
    queryset = Environment.objects.all()
    serializer_class = EnvironmentSerializer
    
    @action(detail=False, methods=['get'])
    def by_project(self, request):
        """根据项目ID获取环境列表"""
        project_id = request.query_params.get('project_id')
        if project_id:
            environments = Environment.objects.filter(project_id=project_id)
            serializer = self.get_serializer(environments, many=True)
            return Response(serializer.data)
        return Response([])


class UserViewSet(viewsets.ModelViewSet):
    """用户管理"""
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserGroupViewSet(viewsets.ModelViewSet):
    """用户组管理"""
    queryset = UserGroup.objects.all()
    serializer_class = UserGroupSerializer


from rest_framework.views import APIView
from django.core.mail import send_mail
from django.conf import settings
import datetime


class SystemInspectionView(APIView):
    """系统巡检API"""
    
    def get(self, request):
        """获取所有主机的巡检数据"""
        hosts = Host.objects.filter(status='online')
        inspection_data = []
        
        for host in hosts:
            try:
                # 建立SSH连接
                client = paramiko.SSHClient()
                client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                
                connect_kwargs = {
                    'hostname': host.ip,
                    'port': host.port,
                    'username': host.username,
                    'timeout': 10
                }
                
                if host.password:
                    connect_kwargs['password'] = host.password
                elif host.ssh_key:
                    from io import StringIO
                    key_file = StringIO(host.ssh_key)
                    connect_kwargs['pkey'] = paramiko.RSAKey.from_private_key(key_file)
                
                client.connect(**connect_kwargs)
                
                # CPU使用率
                stdin, stdout, stderr = client.exec_command("top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | sed 's/%us,//'")
                cpu_output = stdout.read().decode().strip()
                cpu_usage = float(cpu_output) if cpu_output else 0
                
                # 内存使用情况
                stdin, stdout, stderr = client.exec_command("free | grep Mem | awk '{print $3,$2}'")
                mem_output = stdout.read().decode().strip().split()
                mem_used_mb = int(mem_output[0]) // 1024 if len(mem_output) > 0 else 0
                mem_total_mb = int(mem_output[1]) // 1024 if len(mem_output) > 1 else 1
                mem_usage = (mem_used_mb / mem_total_mb * 100) if mem_total_mb > 0 else 0
                
                # 磁盘使用情况
                stdin, stdout, stderr = client.exec_command("df -h / | tail -1 | awk '{print $3,$2,$5}' | sed 's/%//'")
                disk_output = stdout.read().decode().strip().split()
                disk_used = disk_output[0] if len(disk_output) > 0 else '0G'
                disk_total = disk_output[1] if len(disk_output) > 1 else '0G'
                disk_usage = float(disk_output[2]) if len(disk_output) > 2 else 0
                
                # 网络流量（接收和发送，单位MB）
                stdin, stdout, stderr = client.exec_command("cat /proc/net/dev | grep -E 'eth0|ens|eno' | head -1 | awk '{print $2,$10}'")
                net_output = stdout.read().decode().strip().split()
                net_recv_mb = int(net_output[0]) // (1024 * 1024) if len(net_output) > 0 else 0
                net_sent_mb = int(net_output[1]) // (1024 * 1024) if len(net_output) > 1 else 0
                
                # 系统负载
                stdin, stdout, stderr = client.exec_command("uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | sed 's/,//'")
                load_avg = stdout.read().decode().strip()
                
                # 操作系统版本
                stdin, stdout, stderr = client.exec_command("cat /etc/os-release | grep PRETTY_NAME | cut -d'\"' -f2")
                os_version = stdout.read().decode().strip()
                
                client.close()
                
                # 判断健康状态
                status = 'healthy'
                issues = []
                
                if cpu_usage > 80:
                    status = 'warning'
                    issues.append(f'CPU使用率过高: {cpu_usage:.1f}%')
                if mem_usage > 80:
                    status = 'warning'
                    issues.append(f'内存使用率过高: {mem_usage:.1f}%')
                if disk_usage > 80:
                    status = 'critical' if disk_usage > 90 else 'warning'
                    issues.append(f'磁盘使用率过高: {disk_usage:.1f}%')
                
                inspection_data.append({
                    'host_id': host.id,
                    'hostname': host.hostname,
                    'ip': host.ip,
                    'server_type': host.get_server_type_display(),
                    'host_group': host.host_group.name if host.host_group else '未分组',
                    'cpu_usage': round(cpu_usage, 2),
                    'mem_usage': round(mem_usage, 2),
                    'mem_used': f'{mem_used_mb}MB',
                    'mem_total': f'{mem_total_mb}MB',
                    'disk_usage': round(disk_usage, 2),
                    'disk_used': disk_used,
                    'disk_total': disk_total,
                    'net_recv': f'{net_recv_mb}MB',
                    'net_sent': f'{net_sent_mb}MB',
                    'load_avg': load_avg,
                    'os_version': os_version or host.os_version,
                    'status': status,
                    'issues': issues,
                    'check_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                })
                
            except Exception as e:
                inspection_data.append({
                    'host_id': host.id,
                    'hostname': host.hostname,
                    'ip': host.ip,
                    'server_type': host.get_server_type_display(),
                    'host_group': host.host_group.name if host.host_group else '未分组',
                    'status': 'error',
                    'issues': [f'连接失败: {str(e)}'],
                    'check_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                })
        
        return Response({
            'total': len(inspection_data),
            'healthy': len([d for d in inspection_data if d['status'] == 'healthy']),
            'warning': len([d for d in inspection_data if d['status'] == 'warning']),
            'critical': len([d for d in inspection_data if d['status'] == 'critical']),
            'error': len([d for d in inspection_data if d['status'] == 'error']),
            'data': inspection_data
        })
    
    def post(self, request):
        """发送巡检报告邮件"""
        recipients = request.data.get('recipients', [])
        inspection_data = request.data.get('data', [])
        is_alert = request.data.get('alert', False)  # 是否为告警邮件
        
        if not recipients:
            return Response({'error': '请选择收件人'}, status=status.HTTP_400_BAD_REQUEST)
        
        # 生成邮件内容
        if is_alert:
            warning_count = len([d for d in inspection_data if d.get('status') == 'warning'])
            critical_count = len([d for d in inspection_data if d.get('status') == 'critical'])
            subject = f'🚨【告警】系统巡检异常 - {warning_count}个警告, {critical_count}个严重 - {datetime.datetime.now().strftime("%Y-%m-%d %H:%M")}'
        else:
            subject = f'系统巡检报告 - {datetime.datetime.now().strftime("%Y-%m-%d %H:%M")}'
        
        # HTML格式邮件内容
        html_content = f'''
        <html>
        <head>
            <style>
                body {{ font-family: Arial, sans-serif; }}
                table {{ border-collapse: collapse; width: 100%; margin-top: 20px; }}
                th, td {{ border: 1px solid #ddd; padding: 12px; text-align: left; }}
                th {{ background-color: #4CAF50; color: white; }}
                tr:nth-child(even) {{ background-color: #f2f2f2; }}
                .healthy {{ color: #67c23a; font-weight: bold; }}
                .warning {{ color: #e6a23c; font-weight: bold; }}
                .critical {{ color: #f56c6c; font-weight: bold; }}
                .error {{ color: #909399; font-weight: bold; }}
                .summary {{ background-color: #e7f3ff; padding: 15px; margin: 20px 0; border-radius: 5px; }}
            </style>
        </head>
        <body>
            <h2>{'🚨 系统告警通知' if is_alert else '系统巡检报告'}</h2>
            <p>巡检时间: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</p>
            {f'<p style="color: #f56c6c; font-weight: bold; font-size: 16px;">⚠️ 检测到系统异常，请及时处理！</p>' if is_alert else ''}
            
            <div class="summary">
                <h3>巡检摘要</h3>
                <p>总计: {len(inspection_data)} 台主机</p>
                <p class="healthy">健康: {len([d for d in inspection_data if d.get('status') == 'healthy'])} 台</p>
                <p class="warning">警告: {len([d for d in inspection_data if d.get('status') == 'warning'])} 台</p>
                <p class="critical">严重: {len([d for d in inspection_data if d.get('status') == 'critical'])} 台</p>
                <p class="error">错误: {len([d for d in inspection_data if d.get('status') == 'error'])} 台</p>
            </div>
            
            <table>
                <tr>
                    <th>主机名</th>
                    <th>IP地址</th>
                    <th>服务器类型</th>
                    <th>CPU</th>
                    <th>内存</th>
                    <th>磁盘</th>
                    <th>网络(收/发)</th>
                    <th>状态</th>
                    <th>问题</th>
                </tr>
        '''
        
        # 如果是告警邮件，只显示有问题的主机
        display_data = inspection_data
        if is_alert:
            display_data = [d for d in inspection_data if d.get('status') in ['warning', 'critical', 'error']]
        
        for host_data in display_data:
            status_class = host_data.get('status', 'error')
            status_text = {
                'healthy': '正常',
                'warning': '警告',
                'critical': '严重',
                'error': '错误'
            }.get(status_class, '未知')
            
            issues_text = '<br>'.join(host_data.get('issues', [])) if host_data.get('issues') else '-'
            
            cpu = f"{host_data.get('cpu_usage', 0):.1f}%" if 'cpu_usage' in host_data else '-'
            mem = f"{host_data.get('mem_usage', 0):.1f}%" if 'mem_usage' in host_data else '-'
            disk = f"{host_data.get('disk_usage', 0):.1f}%" if 'disk_usage' in host_data else '-'
            net = f"{host_data.get('net_recv', '-')}/{host_data.get('net_sent', '-')}" if 'net_recv' in host_data else '-'
            
            # 告警邮件中高亮显示异常行
            row_style = 'background-color: #fff3cd;' if is_alert and status_class in ['warning', 'critical'] else ''
            
            html_content += f'''
                <tr style="{row_style}">
                    <td>{host_data.get('hostname', '-')}</td>
                    <td>{host_data.get('ip', '-')}</td>
                    <td>{host_data.get('server_type', '-')}</td>
                    <td>{cpu}</td>
                    <td>{mem}</td>
                    <td>{disk}</td>
                    <td>{net}</td>
                    <td class="{status_class}">{status_text}</td>
                    <td>{issues_text}</td>
                </tr>
            '''
        
        html_content += '''
            </table>
            <br>
            <p style="color: #666;">此邮件由CMDB资产管理系统自动生成</p>
        </body>
        </html>
        '''
        
        # 发送邮件
        try:
            send_mail(
                subject=subject,
                message='请使用支持HTML的邮件客户端查看完整报告',
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=recipients,
                html_message=html_content,
                fail_silently=False,
            )
            return Response({'message': '邮件发送成功'})
        except Exception as e:
            return Response({'error': f'邮件发送失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class RecipientViewSet(viewsets.ModelViewSet):
    """邮件收件人管理"""
    queryset = Recipient.objects.all()
    serializer_class = RecipientSerializer
    
    def get_queryset(self):
        """支持根据is_active筛选"""
        queryset = super().get_queryset()
        is_active = self.request.query_params.get('is_active', None)
        if is_active is not None:
            queryset = queryset.filter(is_active=is_active.lower() == 'true')
        return queryset
